package org.ghost.spring.cloud.hystrix.demo.controller;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.ghost.spring.cloud.hystrix.demo.dto.RspDTO;
import org.ghost.spring.cloud.hystrix.demo.dto.weather.WeatherDTO;
import org.ghost.spring.cloud.hystrix.demo.service.IDemoService;
import org.ghost.spring.cloud.hystrix.demo.service.IHelloService;
import org.ghost.spring.cloud.hystrix.demo.service.ITestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping(value = "demo")
public class DemoController extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(DemoController.class);
    @Autowired
    private IHelloService helloService;
    @Autowired
    private ITestService testService;
    @Autowired
    private IDemoService demoService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private EurekaClient eurekaClient;
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @RequestMapping(value = "/hello/{id}", method = RequestMethod.GET)
    public RspDTO helloGet(@PathVariable String id) {
        return this.render(helloService.get(id));
    }

    @HystrixCommand(fallbackMethod = "fallbackGet",
            commandProperties = {
                    // 熔断器在整个统计时间内是否开启的阀值
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
                    // 至少有3个请求才进行熔断错误比率计算
                    /**
                     * 设置在一个滚动窗口中，打开断路器的最少请求数。
                     比如：如果值是20，在一个窗口内（比如10秒），收到19个请求，即使这19个请求都失败了，断路器也不会打开。
                     */
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
                    //当出错率超过50%后熔断器启动
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                    // 熔断器工作时间，超过这个时间，先放一个请求进去，成功的话就关闭熔断，失败就再等一段时间
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
                    // 统计滚动的时间窗口
                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")
            })
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public RspDTO get(@PathVariable String id) {
//        long a = System.currentTimeMillis() % 2 == 0 ? 0 : 1;
//        long b = System.currentTimeMillis() / a;
        return this.render(demoService.get(id));
    }

    public RspDTO fallbackGet(String id) {
        return this.render("fallbackGet");
    }

    @RequestMapping(value = "/process", method = RequestMethod.GET)
    public RspDTO process(@RequestParam String name) {
        return this.render(testService.process(name));
    }

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public RspDTO test(@RequestParam String name) {
        return this.render(testService.test(name));
    }


    @RequestMapping(value = "", method = RequestMethod.POST)
    public RspDTO post(@RequestBody WeatherDTO reqDTO) {
        return this.render(demoService.post(reqDTO));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public RspDTO put(@PathVariable String id, @RequestBody WeatherDTO reqDTO) {
        return this.render(demoService.put(id, reqDTO));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public RspDTO delete(@PathVariable String id) {
        return this.render(demoService.delete(id));
    }

    @RequestMapping(value = "test1", method = RequestMethod.GET)
    public RspDTO get1() throws ExecutionException, InterruptedException {
        return this.render(this.demoService.test1());
    }

    @RequestMapping(value = "test2", method = RequestMethod.GET)
    public RspDTO get2() throws ExecutionException, InterruptedException {
        String url = "http://PROVIDER/demo/test2";
        return restTemplate.getForObject(url, RspDTO.class);
    }

    @RequestMapping(value = "test3", method = RequestMethod.GET)
    public RspDTO get3() {
        return this.demoService.test3();
    }

    @RequestMapping(value = "test4", method = RequestMethod.GET)
    public RspDTO get4() {
        return this.demoService.test4();
    }

    @RequestMapping(value = "test5", method = RequestMethod.GET)
    public RspDTO get5() {
        InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER", false);
        return this.render(instanceInfo);
    }

    @RequestMapping(value = "test6", method = RequestMethod.GET)
    public RspDTO get6() {
        ServiceInstance serviceInstance = loadBalancerClient.choose("PROVIDER");
        return this.render(serviceInstance.getHost() + ":" + serviceInstance.getPort());
    }


    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

